package cn.zuo.service;

import cn.zuo.pojo.Message;
import cn.zuo.pojo.User;
import cn.zuo.service.impl.UserServiceImpl;
import cn.zuo.utils.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;
/**
 * @Author 白白旧维
 * @Date 2021/7/7 11:13
 */
public class Check {

    private static final Logger logger = LoggerFactory.getLogger(Check.class);//得到logger变量

    private ServerSocket ss;
    private UserService userService=new UserServiceImpl();
    private JTextArea jta;
    private Map<String, BigInteger> key;
    private String seed;//AES密钥

    public void setSeed(String seed) {
        this.seed = seed;
    }

    public void connect(JTextArea jta) throws Exception {
        ss = new ServerSocket(9999);
        this.jta = jta;

        System.out.println(PPKeyFactory.getAllKey());
        this.key = PPKeyFactory.getOneKey(System.currentTimeMillis()+new Random().nextLong());

        new Thread(()->{
            try {

                while(true){
                    Socket s = ss.accept();

                    ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());

                    //发送公钥给客户端
                    BigInteger e = key.get("e");
                    BigInteger n = key.get("n");
                    oos.writeObject(new Message("server",null,e+"_"+n));

                    //得到客户端的公钥
                    ObjectInputStream ois1 = new ObjectInputStream(s.getInputStream());
                    Message key_msg = (Message) ois1.readObject();
                    BigInteger client_e = new BigInteger(key_msg.getMsg().split("_")[0]);
                    BigInteger client_n = new BigInteger(key_msg.getMsg().split("_")[1]);
                    PublicKeyPool.setKey_e(key_msg.getSender(),client_e);
                    PublicKeyPool.setKey_n(key_msg.getSender(),client_n);


                    ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
                    Message msg = (Message) ois.readObject();

                    if("login".equals(msg.getReceiver())){
//                        System.out.println("登录.....");
                        login(msg,s);

                    }

                    if("register".equals(msg.getReceiver())){
//                        System.out.println("注册.....");
                        register(msg,s);

                    }

                }

            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                try {
                    ss.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }

    public void close(){
        try {
            ss.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public void login(Message msg,Socket s) throws Exception {
        Map<String,Object> map = new HashMap<>();
        map.put("username",msg.getSender());


        //解密和验证
        String en_password_and_signed_json = msg.getMsg();//加密的信息
        System.out.println("登录密码加密信息："+en_password_and_signed_json);
        System.out.println();
        List<BigInteger> en_password_and_signed = JSONArray.parseArray(en_password_and_signed_json, BigInteger.class);

        String password_and_signed = RSA.decryption_mul(key.get("d"), key.get("n"), en_password_and_signed);//解密

        String password = password_and_signed.split("_")[0];//密码
//        String password_hm1 = MD5.md5(password);//密码杂凑
        String password_hm1 = SHA256.sha256(password);//密码杂凑

        String password_hm_signed_json = password_and_signed.split("_")[1];//签名json
        List<BigInteger> password_hm_signed = JSONArray.parseArray(password_hm_signed_json, BigInteger.class);

        String password_hm2 = RSA.verify_mul_hm(PublicKeyPool.getKey_e(msg.getSender()), PublicKeyPool.getKey_n(msg.getSender()), password_hm_signed);

        if(!password_hm1.equals(password_hm2)){
            System.out.println("签名不一致!!");
            logger.info("登录，签名不一致!!");
            return;
        }

        map.put("password",password);


        User loginUser = userService.login(map);
        ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
        if(loginUser!=null){//1成功，0失败
            if(TalkingPool.getTalking(loginUser.getName())!=null){
                oos.writeObject(new Message("server",msg.getSender(),"-1"));
                return;
            }

            jta.append(loginUser.getName()+"，登录成功!\n");

            //传给客户端用户列表
            String name = loginUser.getName();
            Map<String,Object> map1 = new HashMap<>();
            map1.put("name",name);
            List<User> users = userService.selectName(map1);
            List<String> names = new ArrayList<>();
            for (User user :
                 users) {
                names.add(user.getName());
            }

            oos.writeObject(new Message("server",name, JSON.toJSONString(names)));//我觉得最好不用传整个user过去，不安全

            //新：服务端发送以存有的CtoC公钥给客户端
            System.out.print("服务端发送CtoC公钥给此登录用户");
            Map<String, BigInteger> all_key_e = PublicKeyPool.getClient_key_e();
            Map<String, BigInteger> all_key_n = PublicKeyPool.getClient_key_n();
            Set<String> all_key_e_key = all_key_e.keySet();
            for (String key :
                    all_key_e_key) {
                Message key_msg = new Message(key,null,all_key_e.get(key)+"_"+all_key_n.get(key),"key");
                ObjectOutputStream oos_key_msg = new ObjectOutputStream(s.getOutputStream());
                oos_key_msg.writeObject(key_msg);
                System.out.print("("+key_msg+") ");
                logger.info("("+key_msg+") ");

            }
            System.out.println();
            System.out.println();

            System.out.println("服务端发送随机AES公钥給客户端");
            List<BigInteger> en_aes_key = RSA.encryption_mul(PublicKeyPool.getKey_e(msg.getSender()), PublicKeyPool.getKey_n(msg.getSender()), seed);
            String en_aes_key_json = JSON.toJSONString(en_aes_key);//加密

            Message aes_key_msg = new Message("server",null,en_aes_key_json,"aes");
            ObjectOutputStream oos_aes_msg = new ObjectOutputStream(s.getOutputStream());
            oos_aes_msg.writeObject(aes_key_msg);
            System.out.println("服务器端发送AES密钥...");

//            oos.writeObject(new Message("server",msg.getSender(),"1"));
            //给一个通讯线程
            Talking talking = new Talking(s);
            talking.setSender(loginUser.getName());
            TalkingPool.setTalking(loginUser.getName(),talking);
            talking.start();

        }else{
            oos.writeObject(new Message("server",msg.getSender(),"0"));
        }
    }


    public void register(Message msg,Socket s) throws Exception {
        String name = msg.getSender().split("__")[0];
        String username = msg.getSender().split("__")[1];
//        String password = msg.getMsg();
        Map<String,Object> map = new HashMap<>();
        map.put("name",name);
        map.put("username",username);


        //解密和验证
        String en_password_and_signed_json = msg.getMsg();//加密的信息
        System.out.println(en_password_and_signed_json);
        List<BigInteger> en_password_and_signed = JSONArray.parseArray(en_password_and_signed_json, BigInteger.class);

        String password_and_signed = RSA.decryption_mul(key.get("d"), key.get("n"), en_password_and_signed);//解密

        String password = password_and_signed.split("_")[0];//密码
//        String password_hm1 = MD5.md5(password);//密码杂凑
        String password_hm1 = SHA256.sha256(password);//密码杂凑

        String password_hm_signed_json = password_and_signed.split("_")[1];//签名json
        List<BigInteger> password_hm_signed = JSONArray.parseArray(password_hm_signed_json, BigInteger.class);

        String password_hm2 = RSA.verify_mul_hm(PublicKeyPool.getKey_e(username), PublicKeyPool.getKey_n(username), password_hm_signed);


        if(!password_hm1.equals(password_hm2)) {
            System.out.println("签名不一致!!");
            logger.info("注册，签名不一致!!");
            return;
        }

        map.put("password",password);

        ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());

        User verifyUser = userService.verifyRegister(map);
        if(verifyUser!=null){
            System.out.println("注册失败");
            logger.info("注册失败!!");
            oos.writeObject(new Message("server",username,"0"));
            return;
        }

        int register = userService.register(map);

        if(register>=1){
            jta.append(username+"注册成功!\n");
            System.out.println("注册成功");
            logger.info("注册成功!!!");
            oos.writeObject(new Message("server",username,register+""));//反馈注册信息
        }else{
            System.out.println("注册失败");
            logger.info("注册失败!!!");
            oos.writeObject(new Message("server",username,register+""));
        }
        s.close();
    }


}
